#include "_public.h"

namespace idc
{
    char *deletelchr(char *str, const int cc)
    {
        if (str == nullptr)
            return nullptr;
        char *p = str;
        while (*p == cc)
        {
            *p++;
        }
        memmove(str, p, strlen(p) + 1);
        return str;
    }

    string &deletelchr(string &str, const int cc)
    {
        if (str.empty())
            return str;
        auto find = str.find_first_not_of(cc);
        if (find != 0)
            str.replace(0, find, "");
        return str;
    }

    char *deleterchr(char *str, const int cc)
    {
        if (str == nullptr)
            return nullptr;
        char *p = str;
        char *q = 0;
        while (*p != 0)
        {
            if (*p == cc && q == 0)
            {
                q = p;
            }
            if (*p != cc)
                q = 0;
            *p++;
        }
        if (q != 0)
        {
            *q = 0;
        }
        return str;
    }

    string &deleterchr(string &str, const int cc)
    {
        if (str.empty())
            return str;
        auto find = str.find_last_not_of(cc);
        if (find != 0)
        {
            str.erase(find + 1);
        }
        return str;
    }

    char *deletelrchr(char *str, const int cc)
    {
        if (str == nullptr)
            return nullptr;
        str = deletelchr(str, cc);
        str = deleterchr(str, cc);
        return str;
    }

    string &deletelrchr(string &str, const int cc)
    {
        if (str.empty())
            return str;
        str = deletelchr(str, cc);
        str = deleterchr(str, cc);
        return str;
    }

    char *toupper(char *str)
    {
        if (str == nullptr)
            return str;
        int length = strlen(str);
        for (int i = 0; i < length; i++)
        {
            if (str[i] >= 'a' && str[i] <= 'z')
                str[i] = str[i] - 32;
        }
        return str;
    }

    string &toupper(string &str)
    {
        if (str.empty())
            return str;
        int length = str.size();
        for (int i = 0; i < length; i++)
        {
            if (str[i] >= 'a' && str[i] <= 'z')
                str[i] = str[i] - 32;
        }
        return str;
    }

    char *tolower(char *str)
    {
        if (str == nullptr)
            return str;
        int length = strlen(str);
        for (int i = 0; i < length; i++)
        {
            if (str[i] >= 'A' && str[i] <= 'Z')
                str[i] = str[i] + 32;
        }
        return str;
    }

    string &tolower(string &str)
    {
        if (str.empty())
            return str;
        int length = str.size();
        for (int i = 0; i < length; i++)
        {

            if (str[i] >= 'A' && str[i] <= 'Z')
                str[i] = str[i] + 32;
        }
        return str;
    }

    bool replacestr(string &str, const string &oldstr, const string &newstr, bool bloop)
    {
        if (str.length() == 0 || oldstr.length() == 0 || str.find(oldstr) == string::npos)
            return false;
        if (bloop == true && newstr.length() == 0)
            return false;
        int first = 0;
        int last = 0;
        while (true)
        {
            if (bloop == true)
                first = str.find(oldstr);
            else
                first = str.find(oldstr, last);
            if (first == string::npos)
                break;
            str = str.replace(first, oldstr.length(), newstr);
            if (bloop == false)
                last = first + newstr.length();
        }
        return true;
    }

    bool replacestr(char *str, const string &oldstr, const string &newstr, bool bloop)
    {
        if (str == nullptr)
            return false;
        string strcmp = string(str);
        replacestr(strcmp, oldstr, newstr, bloop);
        strcpy(str, strcmp.c_str());
        str[strcmp.length()] = 0;
        return true;
    }

    string &picknumber(const string &src, string &dest, const bool bsigned, const bool bdot)
    {
        string q;
        for (int i = 0; i < src.length(); i++)
        {
            if (src[i] >= '0' && src[i] <= '9')
                q += src[i];
            else if (src[i] == '.' && bdot)
                q += src[i];
            else if ((src[i] == '+' || src[i] == '-') && bsigned)
                q += src[i];
        }
        dest = q;
        return dest;
    }

    string picknumber(const string &src, const bool bsigned, const bool bdot)
    {
        string dest;
        dest = picknumber(src, dest, bsigned, bdot);
        return dest;
    }

    char *picknumber(const string &src, char *dest, const bool bsigned, const bool bdot)
    {
        if (dest == nullptr)
            return nullptr;
        string q = picknumber(src, bsigned, bdot);
        q.copy(dest, q.length());
        dest[q.length()] = 0;
        return dest;
    }

    bool matchstr(const string &str, const string &rules)
    {
        // 如果匹配规则表达式的内容是空的，返回false。
        if (rules.length() == 0)
            return false;

        // 如果如果匹配规则表达式的内容是"*"，直接返回true。
        if (rules == "*")
            return true;

        int ii, jj;
        int pos1, pos2;
        ccmdstr cmdstr;
        ccmdstr cmdsubstr;

        string filename = str;
        string matchstr = rules;

        // 把字符串都转换成大写后再来比较
        toupper(filename);
        toupper(matchstr);

        cmdstr.splittocmd(matchstr, ",");

        for (ii = 0; ii < cmdstr.size(); ii++)
        {
            // 如果为空，就一定要跳过，否则就会被匹配上。
            if (cmdstr[ii].empty() == true)
                continue;

            pos1 = pos2 = 0;
            cmdsubstr.splittocmd(cmdstr[ii], "*");

            for (jj = 0; jj < cmdsubstr.size(); jj++)
            {
                // 如果是文件名的首部
                if (jj == 0)
                    if (filename.substr(0, cmdsubstr[jj].length()) != cmdsubstr[jj])
                        break;

                // 如果是文件名的尾部
                if (jj == cmdsubstr.size() - 1)
                    if (filename.find(cmdsubstr[jj], filename.length() - cmdsubstr[jj].length()) == string::npos)
                        break;

                pos2 = filename.find(cmdsubstr[jj], pos1);

                if (pos2 == string::npos)
                    break;

                pos1 = pos2 + cmdsubstr[jj].length();
            }

            if (jj == cmdsubstr.size())
                return true;
        }

        return false;
    }

    ccmdstr::ccmdstr(const string &buffer, const string &stept, const bool delete_space)
    {
        splittocmd(buffer, stept, delete_space);
    }

    void ccmdstr::splittocmd(const string &buffer, const string &stept, bool delete_space)
    {
        m_cmdstr.clear();
        string str; // 子串容器
        int first = 0;
        int last = 0;
        while ((last = buffer.find(stept, first)) != string::npos)
        {
            str = buffer.substr(first, last - first);
            if (delete_space)
            {
                deletelrchr(str, ' ');
            }
            m_cmdstr.push_back(str);
            first = last + stept.length();
        }
        if (first < buffer.length())
        {
            str = buffer.substr(first);
            if (delete_space)
            {
                deletelrchr(str, ' ');
            }
            m_cmdstr.push_back(str);
        }
    }

    bool ccmdstr::getvalue(const int ii, string &value, const int maxlen) const
    {
        if (ii < 0 || ii >= m_cmdstr.size() || maxlen < 0)
            return false;
        value = m_cmdstr[ii];
        if (maxlen < value.length())
        {
            value = value.substr(0, maxlen);
        }
        return true;
    }

    bool ccmdstr::getvalue(const int ii, char *value, const int maxlen) const
    {
        if (ii < 0 || ii >= m_cmdstr.size() || maxlen < 0)
            return false;
        string str = m_cmdstr[ii];
        for (int i = 0; i < str.length() && i < maxlen; i++)
        {
            value[i] = str[i];
        }
        value[maxlen - 1] = '\0';
        return true;
    }

    bool ccmdstr::getvalue(const int ii, int &value) const
    {
        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        try
        {
            value = stoi(picknumber(m_cmdstr[ii], true, true));
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool ccmdstr::getvalue(const int ii, unsigned int &value) const
    {
        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        try
        {
            value = static_cast<unsigned int>(stoi(picknumber(m_cmdstr[ii], true, true)));
            return true;
        }
        catch (const std::exception &e)
        {
            std::cerr << e.what() << '\n';
            return false;
        }
    }

    bool ccmdstr::getvalue(const int ii, long &value) const
    {
        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        try
        {
            value = stol(picknumber(m_cmdstr[ii], true, true));
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool ccmdstr::getvalue(const int ii, unsigned long &value) const
    {

        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        try
        {
            value = stoul(picknumber(m_cmdstr[ii], true, true));
            return true;
        }
        catch (std::exception &e)
        {
            return false;
        }
    }

    bool ccmdstr::getvalue(const int ii, double &value) const
    {
        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        try
        {
            value = stod(picknumber(m_cmdstr[ii], true, true));
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool ccmdstr::getvalue(const int ii, float &value) const
    {
        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        try
        {
            value = stof(picknumber(m_cmdstr[ii], true, true));
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool ccmdstr::getvalue(const int ii, bool &value) const
    {
        if (ii < 0 || ii >= m_cmdstr.size())
            return false;
        string str = m_cmdstr[ii];
        toupper(str);
        if (str == "TRUE")
        {
            value = true;
            return true;
        }
        else if (str == "FALSE")
        {
            value = false;
            return true;
        }
        else
            return false;
    }

    ostream &operator<<(ostream &os, const ccmdstr &cc)
    {
        for (int i = 0; i < cc.size(); i++)
        {
            os << cc[i] << ' ';
        }
        return os;
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, string &value, int maxlen)
    {
        if (maxlen < 0)
            return false;
        string str1 = "<" + fieldname + ">";
        string str2 = "</" + fieldname + ">";
        int pos1 = xmlbuffer.find(str1);
        if (pos1 == string::npos)
        {
            return false;
        }
        int pos2 = xmlbuffer.find(str2);
        if (pos2 == string::npos)
        {
            return false;
        }
        int length = pos2 - pos1 - str1.length();
        if ((maxlen > 0) && (length > maxlen))
        {
            length = maxlen;
        }
        value = xmlbuffer.substr(pos1 + str1.length(), length);
        return true;
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, char *value, int maxlen)
    {
        if (value == nullptr)
            return false;
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str))
        {
            if (str.length() > maxlen)
                str = str.substr(0, maxlen);
            strcpy(value, str.c_str());
            return true;
        }
        return false;
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, bool &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str, 5))
        {
            toupper(str);
            if (str == "TRUE")
            {
                value = true;
                return true;
            }
            else if (str == "FALSE")
            {
                value = false;
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, int &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str) == false)
            return false;
        try
        {
            value = stoi(str);
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, unsigned int &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str) == false)
            return false;
        try
        {
            static_cast<unsigned int>(stoi(str));
            return true;
        }
        catch (std::exception &e)
        {
            return false;
        }
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, long &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str) == false)
            return false;
        try
        {
            value = stol(str);
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, unsigned long &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str) == false)
            return false;
        try
        {
            value = stoul(str);
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, double &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str) == false)
            return false;
        try
        {
            value = stod(str);
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    bool getxmlbuffer(const string &xmlbuffer, const string &fieldname, float &value)
    {
        string str;
        if (getxmlbuffer(xmlbuffer, fieldname, str) == false)
            return false;
        try
        {
            value = stof(str);
            return true;
        }
        catch (const std::exception &e)
        {
            return false;
        }
    }

    string &ltime(string &strtime, const string &fmt, int timeval)
    {
        time_t ttime = time(nullptr) + timeval;
        timetostr(ttime, strtime, fmt);
        return strtime;
    }

    char *ltime(char *strtime, const string &fmt, int timeval)
    {
        time_t ttime = time(nullptr) + timeval;
        return timetostr(ttime, strtime, fmt);
    }

    string ltime1(const string &fmt, int timeval)
    {
        time_t ttime = time(nullptr) + timeval;
        return timetostr1(ttime, fmt);
    }

    string &timetostr(const time_t ttime, string &strtime, const string &fmt)
    {
        struct tm t;
        localtime_r(&ttime, &t); // 线程安全
        t.tm_year += 1900;
        t.tm_mon += 1;
        if (fmt == "" || fmt == "yyyy-mm-dd hh24:mi:ss")
        {
            strtime = sformat("%04d-%02d-%02d %02d:%02d:%02d",
                              t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
            return strtime;
        }
        if (fmt == "yyyymmddhh24miss")
        {
            strtime = sformat("%04d%02d%02d%02d%02d%02d",
                              t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
            return strtime;
        }

        if (fmt == "yyyy-mm-dd")
        {
            strtime = sformat("%04d-%02d-%02d",
                              t.tm_year, t.tm_mon, t.tm_mday);
            return strtime;
        }
        if (fmt == "yyyymmdd")
        {
            strtime = sformat("%04d%02d%02d",
                              t.tm_year, t.tm_mon, t.tm_mday);
            return strtime;
        }
        if (fmt == "hh24:mi:ss")
        {
            strtime = sformat("%02d:%02d:%02d",
                              t.tm_hour, t.tm_min, t.tm_sec);
            return strtime;
        }
        if (fmt == "hh24miss")
        {
            strtime = sformat("%02d%02d%02d",
                              t.tm_hour, t.tm_min, t.tm_sec);
            return strtime;
        }
        if (fmt == "hh24:mi")
        {
            strtime = sformat("%02d:%02d",
                              t.tm_hour, t.tm_min);
            return strtime;
        }
        if (fmt == "hh24mi")
        {
            strtime = sformat("%02d%02d",
                              t.tm_hour, t.tm_min);
            return strtime;
        }
        if (fmt == "hh24")
        {
            strtime = sformat("%02d", t.tm_hour);
            return strtime;
        }
        if (fmt == "mi")
        {
            strtime = sformat("%02d", t.tm_min);
            return strtime;
        }
        return strtime;
    }

    char *timetostr(const time_t ttime, char *strtime, const string &fmt)
    {
        if (strtime == nullptr)
            return nullptr;
        string str;
        timetostr(ttime, str, fmt);
        str.copy(strtime, str.length(), 0);
        strtime[str.length()] = '\0';
        return strtime;
    }

    string timetostr1(const time_t ttime, const string &fmt)
    {
        string str;
        timetostr(ttime, str, fmt);
        return str;
    }

    time_t strtotime(const string &strtime)
    {
        string s, yyyy, mm, dd, hh, mi, ss;
        s = picknumber(strtime, yyyy, false, false);
        if (s.length() != 14)
            return -1;
        yyyy = s.substr(0, 4);
        mm = s.substr(4, 2);
        dd = s.substr(6, 2);
        hh = s.substr(8, 2);
        mi = s.substr(10, 2);
        ss = s.substr(12, 2);

        struct tm t;

        try
        {
            t.tm_year = stoi(yyyy) - 1900;
            t.tm_mon = stoi(mm) - 1;
            t.tm_mday = stoi(dd);
            t.tm_hour = stoi(hh);
            t.tm_min = stoi(mi);
            t.tm_sec = stoi(ss);
            t.tm_isdst = -1;
        }
        catch (std::exception &e)
        {
            return -1;
        }
        return mktime(&t);
    }

    bool addtime(const string &in_time, string &out_time, int timeval = 0, const string &fmt)
    {
        time_t ttime;
        if (in_time.empty())
            return false;
        ttime = strtotime(in_time) + timeval;
        timetostr(ttime, out_time, fmt);
        return true;
    }

    bool addtime(const string &in_time, char *out_time, int timeval, const string &fmt)
    {
        time_t ttime;
        if (in_time.empty() || out_time == nullptr)
            return false;
        ttime = strtotime(in_time) + timeval;
        timetostr(ttime, out_time, fmt);
        return true;
    }

    ctimer::ctimer()
    {
        void start();
    }

    void ctimer::start()
    {
        memset(&m_start, 0, sizeof(m_start));
        memset(&m_end, 0, sizeof(m_end));
        gettimeofday(&m_start, nullptr);
    }

    double ctimer::elapsed()
    {
        gettimeofday(&m_end, nullptr);
        string str = sformat("%ld.%06ld", m_end.tv_sec, m_end.tv_usec);
        double end = stod(str);

        str = sformat("%ld.%06ld", m_start.tv_sec, m_start.tv_usec);
        double start = stod(str);

        return end - start;
    }

    bool newdir(const string &pathfilename, const bool bisfilename)
    {
        if (pathfilename.empty())
        {
            return false;
        }
        int pos = 1;
        while (true)
        {
            int pos1 = pathfilename.find('/', pos);
            if (pos1 == string::npos)
            {
                break;
            }
            pos = pos1 + 1;
            string dir = pathfilename.substr(0, pos1);
            if (access(dir.c_str(), F_OK) == -1)
            {
                if (mkdir(dir.c_str(), 0777) == -1)
                {
                    return false;
                }
            }
        }
        if (bisfilename == false)
        {
            if (access(pathfilename.c_str(), 0) == -1)
            {
                if (mkdir(pathfilename.c_str(), 0755) == -1)
                {
                    return false;
                }
            }
        }
        return true;
    }
    bool renamefile(const string &oldfilename, const string &newfilename)
    {
        if (access(oldfilename.c_str(), 0) == -1)
            return false;
        if (newdir(newfilename, true) == false)
        {
            return false;
        }
        if (rename(oldfilename.c_str(), newfilename.c_str()) == -1)
        {
            return false;
        }
        return true;
    }

    bool copyfile(const string &srcfilename, const string &destfilename)
    {
        if (access(srcfilename.c_str(), 0))
            return false;
        cifile ifile;
        cofile ofile;
        int ifilesize = filesize(srcfilename);

        int total_bytes = 0;
        int onread = 0;
        char buffer[5000];

        if (ifile.open(srcfilename, ios::in | ios::binary) == false)
            return false;

        if (ofile.open(destfilename, ios::out | ios::binary) == false)
            return false;

        while (true)
        {
            if ((ifilesize - total_bytes) > 5000)
                onread = 5000;
            else
                onread = ifilesize - total_bytes;

            memset(buffer, 0, sizeof(buffer));
            ifile.read(buffer, onread);
            ofile.write(buffer, onread);

            total_bytes = total_bytes + onread;

            if (total_bytes == ifilesize)
                break;
        }

        ifile.close();
        ofile.closeandrename();

        // 更改文件的修改时间属性
        string strmtime;
        filemtime(srcfilename, strmtime);
        setmtime(destfilename, strmtime);

        return true;
    }

    int filesize(const string &filename)
    {
        struct stat buffer;
        if (stat(filename.c_str(), &buffer) == -1)
            return -1;
        return buffer.st_size;
    }

    bool filemtime(const string &filename, string &mtime, const string &fmt)
    {
        if (access(filename.c_str(), 0) == -1)
            return false;
        struct stat buffer;
        if (stat(filename.c_str(), &buffer) == -1)
            return false;
        string str = timetostr(buffer.st_mtime, mtime, fmt);
        mtime = sformat(str.c_str(), fmt);
        return true;
    }

    bool filemtime(const string &filename, char *mtime, const string &fmt)
    {
        string str;
        if (filemtime(filename, str, fmt) == false)
            return false;
        str.copy(mtime, str.length(), 0);
        mtime[str.length()] = '\0';
        return true;
    }

    bool setmtime(const string &filename, const string &mtime)
    {
        struct utimbuf t;
        t.actime = t.modtime = strtotime(mtime);
        if (utime(filename.c_str(), &t) == -1)
            return false;
        return true;
    }

    void cdir::setfmt(const string &fmt)
    {
        m_fmt = fmt;
    }

    bool cdir::opendir(const string &dirname, const string &rules, const int maxfiles, const bool bandchild, bool bsort)
    {
        m_filelist.clear();
        m_pos = 0;
        if (::opendir(dirname.c_str()) == nullptr && newdir(dirname, false) == false)
            return false;
        bool ret = _opendir(dirname, rules, maxfiles, bandchild);
        if (bsort)
        {
            sort(m_filelist.begin(), m_filelist.end());
        }
        return ret;
    }

    bool cdir::_opendir(const string &dirname, const string &rules, const int maxfiles, const bool bandchild)
    {
        DIR *dir;
        if ((dir = ::opendir(dirname.c_str())) == nullptr)
        {
            m_filelist.clear();
            m_pos = 0;
            return false;
        }
        string strffilename;
        struct dirent *entry;
        while ((entry = ::readdir(dir)) != nullptr)
        {
            if (m_filelist.size() >= maxfiles)
                break;
            if (entry->d_name[0] == '.')
                continue;
            strffilename = dirname + "/" + entry->d_name;
            if (entry->d_type == DT_DIR)
            {
                if (bandchild)
                {
                    if (_opendir(strffilename, rules, maxfiles, true) == false)
                    {
                        closedir(dir);
                        return false;
                    }
                }
            }
            else if (entry->d_type == DT_REG)
            {
                if (matchstr(strffilename, rules))
                {
                    m_filelist.push_back(strffilename);
                }
            }
        }
        closedir(dir);
        return true;
    }

    bool cdir::readdir()
    {
        if (m_pos >= m_filelist.size())
        {
            m_filelist.clear();
            m_pos = 0;
            return false;
        }
        m_ffilename = m_filelist[m_pos];
        int pos1 = m_ffilename.find_last_of('/');
        m_dirname = m_ffilename.substr(0, pos1 + 1);
        m_filename = m_ffilename.substr(pos1 + 1);
        struct stat buffer;
        if (stat(m_ffilename.c_str(), &buffer) == -1)
            return false;
        m_filesize = buffer.st_size;
        m_mtime = timetostr1(buffer.st_mtime, m_fmt);
        m_atime = timetostr1(buffer.st_atime, m_fmt);
        m_ctime = timetostr1(buffer.st_ctime, m_fmt);
        m_pos++;
        return true;
    }

    cdir::~cdir()
    {
        m_filelist.clear();
    }

    bool cofile::open(const string &filename, const bool btmp, const ios::openmode mode, const bool benbuffer)
    {
        ffilename = filename;
        newdir(filename, true);
        if (btmp == true)
        {
            ffilenametmp = filename + ".tmp";
            fout.open(ffilenametmp.c_str(), mode);
        }
        else
        {
            fout.open(filename.c_str(), mode);
        }
        if (benbuffer == false)
        {
            fout << unitbuf;
        }
        if (!fout.is_open())
        {
            return false;
        }
        return true;
    }

    bool cofile::write(void *buf, int bufsize)
    {
        if (!isopen())
            fout.close();
        fout.write((char *)buf, bufsize);
        return fout.good();
    }

    bool cofile::closeandrename()
    {
        if (!isopen())
            return false;
        fout.close();
        if (ffilenametmp.length() > 0)
        {
            if (rename(ffilenametmp.c_str(), ffilename.c_str()) == -1)
            {
                printf("rename(%s,%s) failed.\n", ffilenametmp.c_str(), ffilename.c_str());
                return false;
            }
        }
        return true;
    }

    void cofile::close()
    {
        if (!isopen())
        {
            return;
        }
        fout.close();
        remove(ffilenametmp.c_str());
    }

    bool cifile::open(const string &filename, ios::openmode mode)
    {
        ffilename = filename;
        if (isopen())
        {
            fin.close();
        }
        fin.open(filename.c_str(), mode);
        if (fin.is_open() == false)
        {
            return false;
        }
        return fin.is_open();
    }

    bool cifile::readline(string &str, const string &emz)
    {
        if (fin.is_open() == false)
        {
            return false;
        }
        str.clear();
        string strline;
        while (true)
        {
            getline(fin, strline);
            if (fin.eof())
                return false;
            str += strline;
            if (emz == "")
            {
                return true;
            }
            else
            {
                // 判断是否以emz结尾
                if (str.find(emz, str.length() - emz.length()) != string::npos)
                {
                    return true;
                }
            }
            str += '\n'; // getline会自动删除换行符，所以要补上。
        }
        return false;
    }

    int cifile::read(void *buf, const int len)
    {
        if (fin.is_open() == false)
        {
            return -1;
        }
        fin.read((char *)buf, len);
        return fin.gcount(); // 返回实际读写的字节数
    }

    bool cifile::closeandremove()
    {

        if (fin.is_open())
        {
            fin.close();
        }
        if (remove(ffilename.c_str()) != 0)
        {
            return false;
        }
        return true;
    }

    void cifile::close()
    {
        if (fin.is_open())
        {
            fin.close();
        }
    }

    bool clogfile::open(const string &filename, ios::openmode mode, const bool enbuff, const bool back_up)
    {
        if (!fout.is_open())
        {
            fout.close();
        }
        m_filename = filename;
        m_mode = mode;
        m_backup = back_up;
        m_enbuff = enbuff;

        newdir(m_filename, true);
        fout.open(m_filename, m_mode);
        if (enbuff == false)
        {
            fout << unitbuf;
        }
        return fout.is_open();
    }

    bool clogfile::backup()
    {
        if (m_backup == false)
        {
            return true;
        }
        if (!fout.is_open())
        {
            return false;
        }
        if (fout.tellp() > m_maxsize * 1024 * 1024)
        {
            m_lock.lock();
            fout.close();
            string ffilename = m_filename + ltime1();
            rename(m_filename.c_str(), ffilename.c_str());
            fout.open(m_filename, m_mode);
            if (m_enbuff == false)
            {
                fout << unitbuf;
            }
            m_lock.unlock();
        }
        return true;
    }

    bool ctcpclient::Connect(const unsigned int port, const string &ip)
    {
        if (m_socket != -1)
        {
            Close();
        }
        // 忽略SIGPIPE信号，防止程序异常退出。
        // 如果send到一个disconnected socket上，内核就会发出SIGPIPE信号。这个信号
        // 的缺省处理方法是终止进程，大多数时候这都不是我们期望的。我们重新定义这
        // 个信号的处理方法，大多数情况是直接屏蔽它。
        signal(SIGPIPE, SIG_IGN);

        server_port = port;
        server_ip = ip;
        m_socket = socket(AF_INET, SOCK_STREAM, 0);
        if (m_socket < 0)
        {
            return false;
        }
        struct sockaddr_in server_addr;
        struct hostent *h;
        memset(&server_addr, 0, sizeof(server_addr));
        if ((h = gethostbyname(ip.c_str())) == NULL)
        {
            Close();
            return false;
        }
        server_addr.sin_family = AF_INET;          // 指定通讯协议
        server_addr.sin_port = htons(server_port); // 指定通讯端口
        memset(h, 0, sizeof(h));
        memcpy(h->h_addr, &server_ip[0], server_ip.length()); // 指定通讯IP地址
        if (connect(m_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
        {
            return false;
        }
        return true;
    }

    bool ctcpclient::Read(string &buff, const int itimeout)
    {
        if (m_socket < 0)
        {
            return false;
        }
        return (tcpread(m_socket, buff, itimeout));
    }

    bool ctcpclient::Read(void *buff, const int bufflen, const int itimeout)
    {
        if (m_socket < 0)
        {
            return false;
        }
        return (tcpread(m_socket, buff, bufflen, itimeout));
    }

    bool ctcpclient::Write(const string &buff)
    {
        if (m_socket < 0)
        {
            return false;
        }
        return (tcpwrite(m_socket, buff));
    }

    bool ctcpclient::Write(const void *buff, const int bufflen)
    {
        if (m_socket < 0)
        {
            return false;
        }
        return (tcpwrite(m_socket, (char *)buff, bufflen));
    }

    void ctcpclient::Close()
    {
        if (m_socket > 0)
        {
            close(m_socket);
            m_socket = -1;
        }
    }

    bool ctcpserver::Initserver(const unsigned int port, const int backlog) // backlog:等待连接队列的最大长度
    {
        if (m_listensock != -1)
        {
            Closelisten();
        }

        signal(SIGPIPE, SIG_IGN);

        // 打开SO_REUSEADDR选项，当服务端连接处于TIME_WAIT状态时可以再次启动服务器，
        // 否则bind()可能会不成功，报：Address already in use。
        int opt = 1;
        setsockopt(m_listensock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        m_listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (m_listensock < 0)
        {
            return false;
        }
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;

        m_listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (m_listensock < 0)
        {
            return false;
        }
        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        server_addr.sin_port = htons(port);
        if (bind(m_listensock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
        {
            Closelisten();
            return false;
        }
        if (listen(m_listensock, backlog) != 0)
        {
            Closelisten();
            return false;
        }
        return true;
    }

    bool ctcpserver::Accept()
    {
        if (m_listensock < 0)
        {
            return false;
        }

        sockaddr_len = sizeof(struct sockaddr_in);
        if ((m_connsock = accept(m_listensock, (sockaddr *)&client_addr, (socklen_t *)&sockaddr_len)) < 0)
        {
            return false;
        }
        return true;
    }

    bool ctcpserver::Read(string &buff, const int itimeout)
    {
        if (m_connsock < 0)
        {
            return false;
        }
        return (tcpread(m_connsock, buff, itimeout));
    }

    bool ctcpserver::Read(void *buff, const int bufflen, const int itimeout)
    {
        if (m_connsock < 0)
        {
            return false;
        }
        return (tcpread(m_connsock, buff, bufflen, itimeout));
    }

    bool ctcpserver::Write(const string &buff)
    {
        if (m_connsock < 0)
        {
            return false;
        }
        return (tcpwrite(m_connsock, buff));
    }

    bool ctcpserver::Write(const void *buff, const int bufflen)
    {
        if (m_connsock < 0)
        {
            return false;
        }
        return (tcpwrite(m_connsock, (char *)buff, bufflen));
    }

    char *ctcpserver::getclientip()
    {
        return inet_ntoa(client_addr.sin_addr);
    }

    void ctcpserver::Closelisten()
    {
        if (m_listensock >=0)
        {
            ::close(m_listensock);
            m_listensock = -1;
        }
    }

    void ctcpserver::Closeconn()
    {
        if (m_connsock >=0)
        {
            ::close(m_connsock);
            m_connsock = -1;
        }
    }

    bool tcpread(const int sock, string &buff, const int itimeout)
    {
        if (sock < 0)
        {
            return false;
        }
        if (itimeout > 0)
        {
            struct pollfd fds;
            fds.fd = sock;
            fds.events = POLLIN;
            int ret = poll(&fds, 1, itimeout * 1000);
            if (ret < 0)
            {
                return false;
            }
            if (ret == 0)
            {
                return false;
            }
        }
        if (itimeout <= -1)
        {
            struct pollfd fds;
            fds.fd = sock;
            fds.events = POLLIN;
            int ret = poll(&fds, 1, 0);
            if (ret < 0)
            {
                return false;
            }
            if (ret == 0)
            {
                return false;
            }
        }
        int bufflen = 0;
        if (readn(sock, (char *)&bufflen, 4) == false) // 读取报文长度
        {
            return false;
        }
        buff.resize(bufflen);
        if (readn(sock, &buff[0], bufflen) == false) // 读取报文内容
        {
            return false;
        }
        return true;
    }

    bool tcpread(int sock, void *buff, const int bufflen, const int itimeout)
    {
        if (sock < 0)
        {
            return false;
        }
        if (itimeout > 0)
        {
            struct pollfd fds;
            fds.fd = sock;
            fds.events = POLLIN;
            int ret = poll(&fds, 1, itimeout * 1000);
            if (ret <= 0)
            {
                return false;
            }
        }
        if (itimeout < -1)
        {
            struct pollfd fds;
            fds.fd = sock;
            fds.events = POLLIN;
            int ret = poll(&fds, 1, 0);
            if (ret <= 0)
            {
                return false;
            }
        }
        if (readn(sock, (char *)buff, bufflen) == false) // 读取报文内容
        {
            return false;
        }
        return true;
    }

    bool tcpwrite(const int sock, const string &buff)
    {
        if (sock < 0)
        {
            return false;
        }
        int bufflen = buff.length();
        if (writen(sock, (char *)&bufflen, 4) == false) // 发送报文长度
        {
            return false;
        }
        if (writen(sock, &buff[0], bufflen) == false) // 发送报文内容
        {
            return false;
        }
        return true;
    }

    bool tcpwrite(int sock, const void *buff, const int bufflen)
    {
        if (sock < 0)
        {
            return false;
        }
        if (writen(sock, (char *)buff, bufflen) == false) // 发送报文内容
        {
            return false;
        }
        return true;
    }

    bool readn(const int sockfd, char *buffer, const size_t n)
    {
        int nleft = n; // 剩余需要读取的字节数。
        int idx = 0;   // 已成功读取的字节数。
        int nread;     // 每次调用recv()函数读到的字节数。

        while (nleft > 0)
        {
            if ((nread = recv(sockfd, buffer + idx, nleft, 0)) <= 0)
                return false;

            idx = idx + nread;
            nleft = nleft - nread;
        }

        return true;
    }

    bool writen(const int sockfd, const char *buffer, const size_t n)
    {
        int nleft = n; // 剩余需要写入的字节数。
        int idx = 0;   // 已成功写入的字节数。
        int nwritten;  // 每次调用send()函数写入的字节数。

        while (nleft > 0)
        {
            if ((nwritten = send(sockfd, buffer + idx, nleft, 0)) <= 0)
                return false;

            nleft = nleft - nwritten;
            idx = idx + nwritten;
        }

        return true;
    }

    void closeallsign()
    {
        for (int i = 1; i <= 64; i++)
        {
            signal(i, SIG_IGN);
        }
    }

    bool csemp::init(key_t key, unsigned short value, short semflg)
    {
        if (m_semid != -1) // 信号量已经初始化了
        {
            return false;
        }
        m_semflg = semflg;
        if ((m_semid = semget(key, 1, 0666)) == -1) // 尝试获取信号量
        {
            if (errno == ENOENT) // 未找到信号量
            {
                if ((m_semid = semget(key, 1, IPC_CREAT | 0666 | IPC_EXCL)) == -1) // 创建信号量
                {
                    if (errno == EEXIST) // 信号量已存在
                    {
                        if ((m_semid = semget(key, 1, 0666)) == -1)
                        {
                            perror("init semget 1");
                            return false;
                        }
                        return true;
                    }
                    else
                    {
                        perror("init semget 2");
                        return false;
                    }
                }
                union semun b;
                b.value = value;
                if (semctl(m_semid, 0, SETVAL, b) == -1) // 设置信号量初值
                {
                    perror("init semctl");
                    return false;
                }
            }
            else
            {
                perror("init semget 3");
                return false;
            }
        }
        return true;
    }

    bool csemp::wait(short value)
    {
        if (m_semid == -1)
            return false;
        struct sembuf s;
        s.sem_num = 0;
        s.sem_op = value;
        s.sem_flg = m_semflg;
        if (semop(m_semid, &s, 1) == -1)
        {
            perror("wait semop");
            return false;
        }
        return true;
    }

    bool csemp::post(short value)
    {
        if (m_semid == -1)
            return false;
        struct sembuf s;
        s.sem_num = 0;
        s.sem_op = value;
        s.sem_flg = m_semflg;
        if (semop(m_semid, &s, 1) == -1)
        {
            perror("post semop");
            return false;
        }
        return true;
    }

    int csemp::getvalue()
    {
        return semctl(m_semid, 0, GETVAL);
    }

    bool csemp::destroy()
    {
        if (m_semid == -1)
            return false;
        if (semctl(m_semid, 0, IPC_RMID) == -1)
        {
            perror("destroy semctl");
            return false;
        }
        return true;
    }

    csemp::~csemp()
    {
    }

    cpactive::cpactive()
    {
        shmid=0;
        m_pos = -1;
        m_shm = 0;
    }

    bool cpactive::init(int timeout, string pname, clogfile *logfile)
    {
        if(m_pos!=-1) return true;
        // 创建共享内存
        shmid = shmget((key_t)SHMKEYP, sizeof(struct st_procinfo) * MAXNUM, IPC_CREAT | 0666);
        if (shmid == -1)
        {
            if(logfile==nullptr)  cout<<"创建共享内存失败"<<endl;
            else logfile->write("创建共享内存失败");
            return false;
        }

        // 将共享内存连接到当前进程的地址空间
        m_shm = (st_procinfo *)shmat(shmid, nullptr, 0);
        if (m_shm == (void *)-1)
        {
            if(logfile==nullptr)  cout<<"共享内存连接失败"<<endl;
            else logfile->write("共享内存连接失败");
            return false;
        }

        // // 遍历当前共享内存的占用情况,主要用来调试
        // for (int i = 0; i < 1000; i++)
        // {
        //     if (m_shm[i].pid != 0)
        //     {
        //             cout << "pid=" << m_shm[i].pid << " "
        //              << "name=" << m_shm[i].name << " "
        //              << "timeout=" << m_shm[i].timeout << " "
        //              << "atime=" << m_shm[i].atime << endl;
        //     }
        // }

        st_procinfo info(getpid(), "server1", 30, time(0));
        csemp shmlock;
        if (shmlock.init(SEMKEYP) == -1)
        {
            if(logfile==nullptr) cout << "shmlock init error" << endl;
            else logfile->write("shmlock init error");
            return false;
        }

        shmlock.wait(); // 加锁

        // 在共享内存中查找是否有空闲的地址

        for (int i = 0; i < 1000; i++)
        {
            if (m_shm[i].pid == info.pid)
            {
                m_pos = i;
                break;
            }
        }

        if (m_pos == -1)
        {
            for (int i = 0; i < 1000; i++)
            {
                if (m_shm[i].pid == 0)
                {
                    m_pos = i;
                    break;
                }
            }
        }

        if (m_pos == -1)
        {
            if(logfile==nullptr) cout << "共享内存已满" << endl;
            else logfile->write("共享内存已满");
            shmlock.post(); // 解锁
            return false;
        }

        memcpy(&m_shm[m_pos], &info, sizeof(struct st_procinfo)); // 将当前进程的心跳信息存入共享内存
        shmlock.post();                                          // 解锁
        return true;
    }

    int cpactive::getshmid()
    {
        return shmid;
    }


    int cpactive::getpos()
    {
        return m_pos;
    }
    
    bool cpactive::update()
    {
        if(m_pos==-1)  return false;
        m_shm[m_pos].atime = time(0); // 更新当前进程的心跳时间
        return true;
    }

    cpactive::~cpactive()
    {
        if(m_pos!=-1)
        {
            memset(&m_shm[m_pos], 0, sizeof(struct st_procinfo));
            m_pos=-1;
        }
        if(m_shm!=nullptr)
        {
            shmdt(m_shm);
        }
    }
}